﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;
using NLite.Reflection;
using System.Collections.Specialized;
using NLite.Collections;

namespace NLite.Internal
{
    class HttpContextWrapper
    {
        public static MethodInfo CurrentProperty;
        public static MethodInfo ItemsProperty;
        public static MethodInfo ApplicationProperty;
        public static MethodInfo SessionProperty;
        public static MethodInfo CacheProperty;

        public static Type HttpContextType;

        public static object RealContext
        {
            get
            {
                if (CurrentProperty == null)
                    return null;

                try
                {
                    return CurrentProperty.FastFuncInvoke(null);
                }
                catch
                {
                    return null;
                }
            }
        }

        public static IDictionary Items
        {
            get { return ItemsProperty.FastFuncInvoke(RealContext) as IDictionary; }
        }

        class ApplicationWrapper:IApplication
        {

            static MethodInfo AddMethod;
            static MethodInfo RemoveMethod;
            static MethodInfo GetMethod;
            static MethodInfo GetCountMethod;
            static MethodInfo GetAllKeysMethod;
            static MethodInfo RemoveAllMethod;

            static ApplicationWrapper()
            {
                var applicationStateType = HttpContextWrapper.ApplicationProperty.ReturnType;
                AddMethod = applicationStateType.GetMethod("Set", new Type[] { typeof(string), typeof(object) });
                GetMethod = applicationStateType.GetMethod("Get", new Type[] { typeof(string) });
                RemoveMethod = applicationStateType.GetMethod("Remove", new Type[] { typeof(string) });
                RemoveAllMethod = applicationStateType.GetMethod("RemoveAll");
                GetCountMethod = typeof(ICollection).GetMethod("get_Count");
                GetAllKeysMethod = applicationStateType.GetMethod("get_AllKeys");
            }

            private object Real
            {
            		get{ return HttpContextWrapper.RealApplicationState;}
            }
             
            #region IDataCollection Members

            public object this[object key]
            {
                get
                {
                    Assumes.NotNull(key);
                    var strKey = key.ToString();
                    Assumes.NotNullOrEmpty(strKey);

                    return GetMethod.FastFuncInvoke(HttpContextWrapper.RealApplicationState, strKey);
                }
                set
                {
                    Assumes.NotNull(key);
                    var strKey = key.ToString();
                    Assumes.NotNullOrEmpty(strKey);


                    AddMethod.FastFuncInvoke(HttpContextWrapper.RealApplicationState, strKey, value);
                }
            }

            public bool ContainsKey(object key)
            {
                Assumes.NotNull(key);
                var strKey = key.ToString();
                Assumes.NotNullOrEmpty(strKey);

                var keys = GetAllKeysMethod.FastFuncInvoke(HttpContextWrapper.RealApplicationState) as string[];
                if (keys == null || keys.Length == 0)
                    return false;

                return keys.FirstOrDefault(item => item == strKey) != null;
            }

            public void Remove(object key)
            {
                Assumes.NotNull(key);
                var strKey = key.ToString();
                Assumes.NotNullOrEmpty(strKey);

                RemoveMethod.FastProcInvoke(HttpContextWrapper.RealApplicationState, strKey);
            }

            public int Count
            {
                get { return (int) GetCountMethod.FastFuncInvoke(HttpContextWrapper.RealApplicationState); }
            }

            public void Clear()
            {
                RemoveAllMethod.FastProcInvoke(HttpContextWrapper.RealApplicationState);
            }

            #endregion
        }

        class CacheWrapper : ICache
        {
            public static MethodInfo SetMethod;
            public static MethodInfo GetMethod;
            public static MethodInfo RemoveMethod;
            public static MethodInfo GetDictionaryEnumeratorMethod;
            public static MethodInfo GetCountMethod;

            static CacheWrapper()
            {
                var cacheType = HttpContextWrapper.CacheProperty.ReturnType;

                SetMethod = cacheType.GetMethod("set_Item", new Type[] { typeof(string), typeof(object) });
                GetMethod = cacheType.GetMethod("get_Item", new Type[] { typeof(string) });
                RemoveMethod = cacheType.GetMethod("Remove", new Type[] { typeof(string) });
                GetDictionaryEnumeratorMethod = cacheType.GetMethod("GetEnumerator");
                GetCountMethod = cacheType.GetMethod("get_Count");
            }

            static IDictionaryEnumerator GetDictionaryEnumerator()
            {
                return GetDictionaryEnumeratorMethod.FastFuncInvoke(HttpContextWrapper.RealCacheState) as IDictionaryEnumerator;
            }

            private object Real
            {
            		get{ return HttpContextWrapper.RealCacheState;}
            }
            
            #region IDataCollection Members

            public object this[object key]
            {
                get
                {
                    Assumes.NotNull(key);
                    var strKey = key.ToString();
                    Assumes.NotNullOrEmpty(strKey);

                    return GetMethod.FastFuncInvoke(HttpContextWrapper.RealCacheState, strKey);
                }
                set
                {
                    Assumes.NotNull(key);
                    var strKey = key.ToString();
                    Assumes.NotNullOrEmpty(strKey);


                    SetMethod.FastProcInvoke(HttpContextWrapper.RealCacheState, strKey, value);
                }
            }

            public bool ContainsKey(object key)
            {
                Assumes.NotNull(key);
                var strKey = key.ToString();
                Assumes.NotNullOrEmpty(strKey);

                var it = GetDictionaryEnumerator();
                while (it.MoveNext())
                {
                    if (object.Equals( it.Key,key)) return true;
                }

                return false;
            }

            public void Remove(object key)
            {
                Assumes.NotNull(key);
                var strKey = key.ToString();
                Assumes.NotNullOrEmpty(strKey);

                RemoveMethod.FastProcInvoke(HttpContextWrapper.RealCacheState, strKey);
            }

            public int Count
            {
                get { return (int)GetCountMethod.FastFuncInvoke(HttpContextWrapper.RealCacheState); }
            }

            public void Clear()
            {
                var it = GetDictionaryEnumerator();
                while (it.MoveNext())
                    Remove(it.Key);
            }

            #endregion
        }

        class SessionWrapper : ISession
        {
            public static MethodInfo SetMethod;
            public static MethodInfo GetMethod;
            public static MethodInfo RemoveMethod;
            public static MethodInfo RemoveAllMethod;
            public static MethodInfo GetCountMethod;

            static SessionWrapper()
            {
                var cacheType = HttpContextWrapper.SessionProperty.ReturnType;

                SetMethod = cacheType.GetMethod("set_Item", new Type[] { typeof(string), typeof(object) });
                GetMethod = cacheType.GetMethod("get_Item", new Type[] { typeof(string) });
                RemoveMethod = cacheType.GetMethod("Remove", new Type[] { typeof(string) });
                RemoveAllMethod = cacheType.GetMethod("RemoveAll");
                GetCountMethod = cacheType.GetMethod("get_Count");
            }


            private ICollection Real
            {
            		get{ return HttpContextWrapper.RealSessionState;}
            }
             
            #region IDataCollection Members

            public object this[object key]
            {
                get
                {
                    Assumes.NotNull(key);
                    var strKey = key.ToString();
                    Assumes.NotNullOrEmpty(strKey);

                    return GetMethod.FastFuncInvoke(HttpContextWrapper.RealSessionState, strKey);
                }
                set
                {
                    Assumes.NotNull(key);
                    var strKey = key.ToString();
                    Assumes.NotNullOrEmpty(strKey);


                    SetMethod.FastProcInvoke(HttpContextWrapper.RealSessionState, strKey, value);
                }
            }

            public bool ContainsKey(object key)
            {
                Assumes.NotNull(key);
                var strKey = key.ToString();
                Assumes.NotNullOrEmpty(strKey);

                var it = HttpContextWrapper.RealSessionState.GetProperty<NameObjectCollectionBase.KeysCollection>("Keys").GetEnumerator();
                while (it.MoveNext())
                {
                	if (object.Equals(it.Current , key)) return true;
                }

                return false;
            }

            public void Remove(object key)
            {
                Assumes.NotNull(key);
                var strKey = key.ToString();
                Assumes.NotNullOrEmpty(strKey);

                RemoveMethod.FastProcInvoke(HttpContextWrapper.RealSessionState, strKey);
            }

            public int Count
            {
                get { return (int)GetCountMethod.FastFuncInvoke(HttpContextWrapper.RealSessionState); }
            }

            public void Clear()
            {
                RemoveAllMethod.FastProcInvoke(HttpContextWrapper.RealSessionState);
            }

            #endregion
        }

        static NameObjectCollectionBase RealApplicationState
        {
            get { return ApplicationProperty.FastFuncInvoke(RealContext) as NameObjectCollectionBase; }
        }

        public static IApplication ApplicationState
        {
            get { return new ApplicationWrapper(); }
        }

        static object RealCacheState
        {
            get { return CacheProperty.FastFuncInvoke(RealContext); }
        }

        public static ICache CacheState
        {
            get { return new CacheWrapper(); }
        }

        static ICollection RealSessionState
        {
            get { return (ICollection)SessionProperty.FastFuncInvoke(RealContext) ; }
        }

        public static ISession SessionState
        {
            get { return new SessionWrapper(); }
        }
    }

    sealed class HashtableDataCollection : Hashtable, IDataCollection { }
}
